package scenic;

import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GraphicsEnvironment;
import java.awt.Rectangle;
import java.awt.event.HierarchyEvent;
import java.awt.event.HierarchyListener;

import javax.swing.JFrame;
import javax.swing.JRootPane;
import javax.swing.RepaintManager;

import scenic.awt.ScenicGraphics2D;
import scenic.jni.XCanvas;
import scenic.swing.ScenicRepaintManager;
import scenic.swing.ScenicRootPane;

public class ScenicJFrame extends JFrame implements SceneParent {
	static {
		scenic.jni.RenderCanvas.loadLibrary();
		RepaintManager.setCurrentManager(new ScenicRepaintManager(RepaintManager.currentManager(null)));
/*		try {
			UIManager.setLookAndFeel(new ScenicLookAndFeel(UIManager.getLookAndFeel()));
		} catch (UnsupportedLookAndFeelException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} */
	}
	
	private static final long serialVersionUID = 970842755539037115L;
	
	int id = 0;
	private int width;
	private int height;
	private ScenicImage renderTarget = new ScenicImage(1, 1, Format.A8B8G8R8, 
			ImageOptions.RENDER_TARGET);
	
	public int getId() {
		return id;
	}
	
	private class CanvasHierarchyListener implements HierarchyListener {
		public void hierarchyChanged(HierarchyEvent e) {
			if((e.getChangeFlags() & HierarchyEvent.SHOWING_CHANGED) != 0) {
				if(!isShowing())
					release();
			}
		}
	}
	
	public ScenicJFrame()
	{
		super(XCanvas.findConfiguration(GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice()));
		addHierarchyListener(new CanvasHierarchyListener());
	}
	
	public ScenicJFrame(String title)
	{
		super(XCanvas.findConfiguration(GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice()));
		addHierarchyListener(new CanvasHierarchyListener());
		setTitle(title);
	}
	
	private void updateConfig() {
		if(id == 0) {
			id = nativeCreate();
			width = getWidth();
			height = getHeight();
		}
		else if(width != getWidth() || height != getHeight()) {
			nativeReset(id);
			width = getWidth();
			height = getHeight();
		}
		if(width != renderTarget.getWidth() || 
			height != renderTarget.getHeight()) {
			renderTarget.create(width, height, Format.A8R8G8B8, ImageOptions.RENDER_TARGET);
		}
	}
	
	public void release() {
		if(id != 0) {
			nativeRelease(id);
			id = 0;
		}		
	}
	
	public void finalize() {
		release();
	}
	
/*	public void update(Graphics g) {
		paint(g);
	} */
	
	public int getContext() {
		return id;
	}
	
	public boolean getIsIntialized() {
		return id != 0;
	}
	
	
	@Override
	protected JRootPane createRootPane() {
		return new ScenicRootPane(this);
	} 

	private boolean insidePaint = false;
	
	public Graphics2D getGraphics() {
		return new ScenicGraphics2D(CommandBuffer.getInstance().createContext(renderTarget));
	}

	@Override
	public void update(Graphics g) {
//		System.out.println("Frame update");
		paint(g);
	}
	
	@Override
	public void repaint() {
//		System.out.println("Frame repaint");
		super.repaint();
	}
	
	@Override
	public void paint(Graphics g) {
		long time = System.currentTimeMillis();

		updateConfig();
		
		System.out.println("paint");
		getRootPane().paint(new ScenicGraphics2D(CommandBuffer.getInstance().createContext(renderTarget)));
		displayRenderTarget();
		long time2 = System.currentTimeMillis();
//		System.out.println("Scene creation " + (time2 - time) + "ms");
		long time3 = System.currentTimeMillis();
//		System.out.println("Scene rendering " + (time3 - time2) + "ms");
	}
	
	/**
	 * This method is automatically called when the scene graph is changed.
	 * Do not call this method yourself. The scene is automatically
	 * repainted whenever it changes.
	 */
	public void childChanged(Rectangle area) {
	}
	
	ScenicImage getRenderTarget() {
		return renderTarget;
	}
	
	public void displayRenderTarget()
	{		
		if(id == 0)
			return;
		Graphics2D g = new ScenicGraphics2D(CommandBuffer.getInstance().createContext(this));
		
		g.drawImage(renderTarget, 0, 0, null);
		g.dispose();
/*		Rectangle r = getBounds();		
		DrawContext context = new DrawContext();
		Rectangle bounds = new Rectangle(0, 0, r.width, r.height);
		SceneImage scene = new SceneImage(renderTarget);
		
		context.root = this;
		context.renderingInstance = new Object();
		context.width = r.width;
		context.height = r.height;
		context.renderer = new Renderer();
		context.context = context.renderer.createContextForCanvas(this);
		
		context.renderer.enterCriticalSection();
		try {
			if(!context.renderer.beginScene(context.context)) {
				System.out.println("beginScene failed");
				return;
			}
			scene.draw(context, new AffineTransform(), bounds);

			context.renderer.endScene(context.context);
			context.renderer.present(context.context);
		} finally {
			context.renderer.deleteContext(context.context);
			context.renderer.leaveCriticalSection();			
		} */
	}

	private native int nativeCreate();
	private native void nativeReset(int id);
	private native void nativeRelease(int id);
}
